<!DOCTYPE html>
<html>
<head>
    

    

    



    <meta charset="utf-8">
    
    
    
    <title>lucene | 尼古拉斯-鱼丸博客 | 喝酒、吃肉、不赌</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
    <meta name="theme-color" content="#3F51B5">
    
    
    <meta name="keywords" content="lucene">
    <meta name="description" content="什么是Lucene?Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包，是一个全文检索引擎的架构，提供了完整的查询引擎和索引引擎，部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包，以方便的在目标系统中实现全文检索的功能，或者是以此为基础建立起完整的全文检索引擎。因而LuceneLuceneLuceneLuceneLuceneLucene是 基于索引">
<meta name="keywords" content="lucene">
<meta property="og:type" content="article">
<meta property="og:title" content="lucene">
<meta property="og:url" content="http://fish_08.oschina.io/2017/07/06/lucene/index.html">
<meta property="og:site_name" content="尼古拉斯-鱼丸博客">
<meta property="og:description" content="什么是Lucene?Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包，是一个全文检索引擎的架构，提供了完整的查询引擎和索引引擎，部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包，以方便的在目标系统中实现全文检索的功能，或者是以此为基础建立起完整的全文检索引擎。因而LuceneLuceneLuceneLuceneLuceneLucene是 基于索引">
<meta property="og:updated_time" content="2017-07-06T08:36:44.157Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="lucene">
<meta name="twitter:description" content="什么是Lucene?Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包，是一个全文检索引擎的架构，提供了完整的查询引擎和索引引擎，部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包，以方便的在目标系统中实现全文检索的功能，或者是以此为基础建立起完整的全文检索引擎。因而LuceneLuceneLuceneLuceneLuceneLucene是 基于索引">
    
        <link rel="alternative" href="/atom.xml" title="尼古拉斯-鱼丸博客" type="application/atom+xml">
    
    <link rel="shortcut icon" href="/favicon.ico">
    <link rel="stylesheet" href="/css/style.css?v=1.6.7">
    <script>window.lazyScripts=[]</script>
</head>

<body>
    <div id="loading" class="active"></div>

    <aside id="menu" class="hide" >
  <div class="inner flex-row-vertical">
    <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menu-off">
        <i class="icon icon-lg icon-close"></i>
    </a>
    <div class="brand-wrap">
      <div class="brand">
        <a href="/" class="avatar waves-effect waves-circle waves-light">
          <img src="/img/avatar.jpg">
        </a>
        <hgroup class="introduce">
          <h5 class="nickname">于亮</h5>
          <a href="mailto:136214289@qq.com" title="136214289@qq.com" class="mail">136214289@qq.com</a>
        </hgroup>
      </div>
    </div>
    <div class="scroll-wrap flex-col">
      <ul class="nav">
        
            <li class="waves-block waves-effect">
              <a href="/"  >
                <i class="icon icon-lg icon-home"></i>
                主页
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/archives"  >
                <i class="icon icon-lg icon-archives"></i>
                文档
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/tags"  >
                <i class="icon icon-lg icon-tags"></i>
                标签
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="http://git.oschina.net/fish_08" target="_blank" >
                <i class="icon icon-lg icon-github"></i>
                Github
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="http://weibo.com/2837335591/profile?rightmod=1&wvr=6&mod=personinfo" target="_blank" >
                <i class="icon icon-lg icon-weibo"></i>
                Weibo
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/custom"  >
                <i class="icon icon-lg icon-link"></i>
                测试
              </a>
            </li>
        
      </ul>
    </div>
  </div>
</aside>

    <main id="main">
        <header class="top-header" id="header">
    <div class="flex-row">
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light on" id="menu-toggle">
          <i class="icon icon-lg icon-navicon"></i>
        </a>
        <div class="flex-col header-title ellipsis">lucene</div>
        
        <div class="search-wrap" id="search-wrap">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
                <i class="icon icon-lg icon-chevron-left"></i>
            </a>
            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="search">
                <i class="icon icon-lg icon-search"></i>
            </a>
        </div>
        
        
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menuShare">
            <i class="icon icon-lg icon-share-alt"></i>
        </a>
        
    </div>
</header>
<header class="content-header post-header">

    <div class="container fade-scale">
        <h1 class="title">lucene</h1>
        <h5 class="subtitle">
            
                <time datetime="2017-07-06T01:57:56.000Z" itemprop="datePublished" class="page-time">
  2017-07-06
</time>


            
        </h5>
    </div>

    

</header>


<div class="container body-wrap">
    
    <aside class="post-widget">
        <nav class="post-toc-wrap" id="post-toc">
            <h4>TOC</h4>
            <ol class="post-toc"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#什么是Lucene"><span class="post-toc-number">1.</span> <span class="post-toc-text">什么是Lucene?</span></a></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#Lucene应用场景？"><span class="post-toc-number">2.</span> <span class="post-toc-text">Lucene应用场景？</span></a></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#Lucene的使用"><span class="post-toc-number">3.</span> <span class="post-toc-text">Lucene的使用</span></a></li></ol>
        </nav>
    </aside>
    
<article id="post-lucene"
  class="post-article article-type-post fade" itemprop="blogPost">

    <div class="post-card">
        <h1 class="post-card-title">lucene</h1>
        <div class="post-meta">
            <time class="post-time" title="2017年07月06日 9:57" datetime="2017-07-06T01:57:56.000Z"  itemprop="datePublished">2017-07-06</time>

            


            
<span id="busuanzi_container_page_pv" title="文章总阅读量" style='display:none'>
    <i class="icon icon-eye icon-pr"></i><span id="busuanzi_value_page_pv"></span>
</span>


            

        </div>
        <div class="post-content" id="post-content" itemprop="postContent">
            <h3 id="什么是Lucene"><a href="#什么是Lucene" class="headerlink" title="什么是Lucene?"></a>什么是Lucene?</h3><p>Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包，是一个全文检索引擎的架构，提供了完整的查询引擎和索引引擎，部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包，以方便的在目标系统中实现全文检索的功能，或者是以此为基础建立起完整的全文检索引擎。因而LuceneLuceneLuceneLuceneLuceneLucene是 基于索引库收的全文搜工具类，不一个完整擎或者应用。<br>Lucene 仅仅是一个java工具包，不是一个全文搜索的应用，不是成形的应用，例如网路爬虫，网站搜索引擎等。</p>
<h3 id="Lucene应用场景？"><a href="#Lucene应用场景？" class="headerlink" title="Lucene应用场景？"></a>Lucene应用场景？</h3><ol>
<li>全文检索<br>1.1 什么是全文检索？<br>目前人们生活中出现的数据总的来说分为两类：结构化数据和非结构化数据。<br>很容易理解，结构化数据是有固定格式和结构的或者有限长度的数据，比如数据库，元数据等。非结构化数据则是不定长或者没有固定格式的数据，如图片，邮件，文档等。还有一种较少的分类为半结构化数据，如XML，HTML等，在一定程度上我们可以将其按照结构化数据来处理，也可以抽取纯文本按照非结构化数据来处理。<br>对结构化数据的搜索：如对数据库的搜索，用SQL语句。再如对元数据的搜索，如利用windows搜索对文件名，类型，修改时间进行搜索等。<br>对非结构化数据的搜索：如利用windows的搜索也可以搜索文件内容，Linux下的grep命令，再如用Google和百度可以搜索大量内容数据。<br>非结构化数据又称为全文数据，对其搜索主要有两种方式:<br>1）顺序扫描法（SerialScanning）：顾名思义，要找内容包含某一个字符串的文档，就挨着文档一个个找，对照每一个文档从头到尾，一直扫描，指导扫描完所有的文档。类似于Windows中搜索文件的功能。<br>2）索引搜索。有人可能会说，对非结构化数据顺序扫描很慢，对结构化数据的搜索却相对较快（由于结构化数据有一定的结构可以采取一定的搜索算法加快速度），那么把我们的非结构化数据想办法弄得有一定结构不就行了吗？<br>这种想法很天然，却构成了全文检索的基本思路，也即将非结构化数据中的一部分信息提取出来，重新组织，使其变得有一定结构，然后对此有一定结构的数据进行搜索，从而达到搜索相对较快的目的。<br>比如我们的电话簿，从电话簿中查找联系人，我们根据首字母拼音可以索引定位到某一个联系人。<br>这种先建立索引，再对索引进行搜索的过程就叫全文检索(Full-text Search)。</li>
</ol>
<h3 id="Lucene的使用"><a href="#Lucene的使用" class="headerlink" title="Lucene的使用"></a>Lucene的使用</h3><p>全文检索大体分两个过程，索引创建(Indexing)和搜索索引(Search)。<br>索引创建：将现实世界中所有的结构化和非结构化数据提取信息，创建索引的过程。<br>搜索索引：就是得到用户的查询请求，搜索创建的索引，然后返回结果的过程。</p>
<ol>
<li>索引里面究竟存些什么？(Index)<br>索引里面究竟需要存些什么呢？<br>首先我们来看为什么顺序扫描的速度慢：<br>其实是由于我们想要搜索的信息和非结构化数据中所存储的信息不一致造成的。<br>非结构化数据中所存储的信息是每个文件包含哪些字符串，也即已知文件，欲求字符串相对容易，也即是从文件到字符串的映射。而我们想搜索的信息是哪些文件包含此字符串，也即已知字符串，欲求文件，也即从字符串到文件的映射。两者恰恰相反。于是如果索引总能够保存从字符串到文件的映射，则会大大提高搜索速度。<br>由于从字符串到文件的映射是文件到字符串映射的反向过程，于是保存这种信息的索引称为反向索引。<br>反向索引的所保存的信息一般如下：<br>假设我的文档集合里面有100篇文档，为了方便表示，我们为文档编号从1到100，得到下面的结构<br>inverted index<br>左边保存的是一系列字符串，称为词典。<br>每个字符串都指向包含此字符串的文档(Document)链表，此文档链表称为倒排表(Posting List)。<br>有了索引，便使保存的信息和要搜索的信息一致，可以大大加快搜索的速度。<br>比如说，我们要寻找既包含字符串“lucene”又包含字符串“solr”的文档，我们只需要以下几步：</li>
<li>取出包含字符串“lucene”的文档链表。</li>
<li>取出包含字符串“solr”的文档链表。</li>
<li>通过合并链表，找出既包含“lucene”又包含“solr”的文件。<br>inverted index merge<br>看到这个地方，有人可能会说，全文检索的确加快了搜索的速度，但是多了索引的过程，两者加起来不一定比顺序扫描快多少。的确，加上索引的过程，全文检索不一定比顺序扫描快，尤其是在数据量小的时候更是如此。而对一个很大量的数据创建索引也是一个很慢的过程。<br>然而两者还是有区别的，顺序扫描是每次都要扫描，而创建索引的过程仅仅需要一次，以后便是一劳永逸的了，每次搜索，创建索引的过程不必经过，仅仅搜索创建好的索引就可以了。<br>这也是全文搜索相对于顺序扫描的优势之一：一次索引，多次使用。</li>
</ol>
<ol>
<li>如何创建索引？(Indexing)<br>全文检索的索引创建过程一般有以下几步：<br>第一步：一些要索引的原文档(Document)。<br>为了方便说明索引创建过程，这里特意用两个文件为例：<br>文件一：Students should be allowed to go out with their friends, but not allowed to drink beer.<br>文件二：My friend Jerry went to school to see his students but found them drunk which is not allowed.</li>
</ol>
<p>第二步：将原文档传给分次组件(Tokenizer)。<br>分词组件(Tokenizer)会做以下几件事情(此过程称为Tokenize)：</p>
<ol>
<li>将文档分成一个一个单独的单词。</li>
<li>去除标点符号。</li>
<li>去除停词(Stop word)。<br>所谓停词(Stop word)就是一种语言中最普通的一些单词，由于没有特别的意义，因而大多数情况下不能成为搜索的关键词，因而创建索引时，这种词会被去掉而减少索引的大小。<br>英语中挺词(Stop word)如：“the”,“a”，“this”等。<br>对于每一种语言的分词组件(Tokenizer)，都有一个停词(stop word)集合。<br>经过分词(Tokenizer)后得到的结果称为词元(Token)。<br>在我们的例子中，便得到以下词元(Token)：<br>“Students”，“allowed”，“go”，“their”，“friends”，“allowed”，“drink”，“beer”，“My”，“friend”，“Jerry”，<br>“went”，“school”，“see”，“his”，“students”，“found”，“them”，“drunk”，“allowed”。<br>第三步：将得到的词元(Token)传给语言处理组件(Linguistic Processor)。<br>语言处理组件(linguistic processor)主要是对得到的词元(Token)做一些同语言相关的处理。<br>对于英语，语言处理组件(Linguistic Processor)一般做以下几点：</li>
<li>变为小写(Lowercase)。</li>
<li>将单词缩减为词根形式，如“cars”到“car”等。这种操作称为：stemming。</li>
<li>将单词转变为词根形式，如“drove”到“drive”等。这种操作称为：lemmatization。<br>Stemming 和 lemmatization的异同：<br>相同之处：Stemming和lemmatization都要使词汇成为词根形式。<br>两者的方式不同：<br>Stemming采用的是“缩减”的方式：“cars”到“car”，“driving”到“drive”。<br>Lemmatization采用的是“转变”的方式：“drove”到“drove”，“driving”到“drive”。<br>两者的算法不同：<br>Stemming主要是采取某种固定的算法来做这种缩减，如去除“s”，去除“ing”加“e”，将“ational”变为“ate”，将“tional”变为“tion”。<br>Lemmatization主要是采用保存某种字典的方式做这种转变。比如字典中有“driving”到“drive”，“drove”到“drive”，“am, is, are”到“be”的映射，做转变时，只要查字典就可以了。<br>Stemming和lemmatization不是互斥关系，是有交集的，有的词利用这两种方式都能达到相同的转换。<br>语言处理组件(linguistic processor)的结果称为词(Term)。<br>在我们的例子中，经过语言处理，得到的词(Term)如下：<br>“student”，“allow”，“go”，“their”，“friend”，“allow”，“drink”，“beer”，“my”，“friend”，“jerry”，“go”，“school”，<br>“see”，“his”，“student”，“find”，“them”，“drink”，“allow”。<br>也正是因为有语言处理的步骤，才能使搜索drove，而drive也能被搜索出来。</li>
</ol>
<p>第四步：将得到的词(Term)传给索引组件(Indexer)。<br>索引组件(Indexer)主要做以下几件事情：</p>
<ol>
<li><p>利用得到的词(Term)创建一个字典。<br>在我们的例子中字典如下：<br>Term    Document ID<br>student    1<br>allow    1<br>go    1<br>their    1<br>friend    1<br>allow    1<br>drink    1<br>beer    1<br>my    2<br>friend    2<br>jerry    2<br>go    2<br>school    2<br>see    2<br>his    2<br>student    2<br>find    2<br>them    2<br>drink    2<br>allow    2</p>
</li>
<li><p>对字典按字母顺序进行排序。<br>Term    Document ID<br>allow    1<br>allow    1<br>allow    2<br>beer    1<br>drink    1<br>drink    2<br>find    2<br>friend    1<br>friend    2<br>go    1<br>go    2<br>his    2<br>jerry    2<br>my    2<br>school    2<br>see    2<br>student    1<br>student    2<br>their    1<br>them    2</p>
</li>
<li><p>合并相同的词(Term)成为文档倒排(Posting List)链表。<br>postinglist<br>在此表中，有几个定义：<br>Document Frequency 即文档频次，表示总共有多少文件包含此词(Term)。<br>Frequency 即词频率，表示此文件中包含了几个此词(Term)。<br>所以对词(Term) “allow”来讲，总共有两篇文档包含此词(Term)，从而词(Term)后面的文档链表总共有两项，第一项表示包含“allow”的第一篇文档，即1号文档，此文档中，“allow”出现了2次，第二项表示包含“allow”的第二个文档，是2号文档，此文档中，“allow”出现了1次。<br>到此为止，索引已经创建好了，我们可以通过它很快的找到我们想要的文档。<br>而且在此过程中，我们惊喜地发现，搜索“drive”，“driving”，“drove”，“driven”也能够被搜到。因为在我们的索引中，“driving”，“drove”，“driven”都会经过语言处理而变成“drive”，在搜索时，如果您输入“driving”，输入的查询语句同样经过我们这里的一到三步，从而变为查询“drive”，从而可以搜索到想要的文档。</p>
</li>
<li><p>如何对索引进行搜索？(Search)<br>到这里似乎我们可以宣布“我们找到想要的文档了”。<br>然而事情并没有结束，找到了仅仅是全文检索的一个方面。不是吗？如果仅仅只有一个或十个文档包含我们查询的字符串，我们的确找到了。然而如果结果有一千个，甚至成千上万个呢？那个又是您最想要的文件呢？<br>打开Google吧，比如说您想在微软找份工作，于是您输入“Microsoft job”，您却发现总共有22600000个结果返回。好大的数字呀，突然发现找不到是一个问题，找到的太多也是一个问题。在如此多的结果中，如何将最相关的放在最前面呢？<br>当然Google做的很不错，您一下就找到了jobs at Microsoft。想象一下，如果前几个全部是“Microsoft does a good job at software industry…”将是多么可怕的事情呀。<br>如何像Google一样，在成千上万的搜索结果中，找到和查询语句最相关的呢？<br>如何判断搜索出的文档和查询语句的相关性呢？<br>这要回到我们第三个问题：如何对索引进行搜索？<br>搜索主要分为以下几步：<br>第一步：用户输入查询语句。<br>查询语句同我们普通的语言一样，也是有一定语法的。<br>不同的查询语句有不同的语法，如SQL语句就有一定的语法。<br>查询语句的语法根据全文检索系统的实现而不同。最基本的有比如：AND, OR, NOT等。<br>举个例子，用户输入语句：lucene AND learned NOT hadoop。<br>说明用户想找一个包含lucene和learned然而不包括hadoop的文档。</p>
</li>
</ol>
<p>第二步：对查询语句进行词法分析，语法分析，及语言处理。<br>由于查询语句有语法，因而也要进行语法分析，语法分析及语言处理。</p>
<ol>
<li><p>词法分析主要用来识别单词和关键字。<br>如上述例子中，经过词法分析，得到单词有lucene，learned，hadoop, 关键字有AND, NOT。<br>如果在词法分析中发现不合法的关键字，则会出现错误。如lucene AMD learned，其中由于AND拼错，导致AMD作为一个普通的单词参与查询。</p>
</li>
<li><p>语法分析主要是根据查询语句的语法规则来形成一棵语法树。<br>如果发现查询语句不满足语法规则，则会报错。如lucene NOT AND learned，则会出错。</p>
</li>
<li><p>语言处理同索引过程中的语言处理几乎相同。<br>如learned变成learn等。<br>经过第二步，我们得到一棵经过语言处理的语法树</p>
</li>
</ol>
<p>第三步：搜索索引，得到符合语法树的文档。<br>此步骤有分几小步：<br>首先，在反向索引表中，分别找出包含lucene，learn，hadoop的文档链表。<br>其次，对包含lucene，learn的链表进行合并操作，得到既包含lucene又包含learn的文档链表。<br>然后，将此链表与hadoop的文档链表进行差操作，去除包含hadoop的文档，从而得到既包含lucene又包含learn而且不包含hadoop的文档链表。<br>此文档链表就是我们要找的文档。</p>
<p>第四步：根据得到的文档和查询语句的相关性，对结果进行排序。<br>虽然在上一步，我们得到了想要的文档，然而对于查询结果应该按照与查询语句的相关性进行排序，越相关者越靠前。<br>如何计算文档和查询语句的相关性呢？<br>不如我们把查询语句看作一片短小的文档，对文档与文档之间的相关性(relevance)进行打分(scoring)，分数高的相关性好，就应该排在前面。<br>那么又怎么对文档之间的关系进行打分呢？<br>这可不是一件容易的事情，首先我们看一看判断人之间的关系吧。<br>首先看一个人，往往有很多要素，如性格，信仰，爱好，衣着，高矮，胖瘦等等。<br>其次对于人与人之间的关系，不同的要素重要性不同，性格，信仰，爱好可能重要些，衣着，高矮，胖瘦可能就不那么重要了，所以具有相同或相似性格，信仰，爱好的人比较容易成为好的朋友，然而衣着，高矮，胖瘦不同的人，也可以成为好的朋友。<br>因而判断人与人之间的关系，首先要找出哪些要素对人与人之间的关系最重要，比如性格，信仰，爱好。其次要判断两个人的这些要素之间的关系，比如一个人性格开朗，另一个人性格外向，一个人信仰佛教，另一个信仰上帝，一个人爱好打篮球，另一个爱好踢足球。我们发现，两个人在性格方面都很积极，信仰方面都很善良，爱好方面都爱运动，因而两个人关系应该会很好。</p>
<p>我们再来看看公司之间的关系吧。<br>首先看一个公司，有很多人组成，如总经理，经理，首席技术官，普通员工，保安，门卫等。<br>其次对于公司与公司之间的关系，不同的人重要性不同，总经理，经理，首席技术官可能更重要一些，普通员工，保安，门卫可能较不重要一点。所以如果两个公司总经理，经理，首席技术官之间关系比较好，两个公司容易有比较好的关系。然而一位普通员工就算与另一家公司的一位普通员工有血海深仇，怕也难影响两个公司之间的关系。<br>因而判断公司与公司之间的关系，首先要找出哪些人对公司与公司之间的关系最重要，比如总经理，经理，首席技术官。其次要判断这些人之间的关系，不如两家公司的总经理曾经是同学，经理是老乡，首席技术官曾是创业伙伴。我们发现，两家公司无论总经理，经理，首席技术官，关系都很好，因而两家公司关系应该会很好。</p>
<p>分析了两种关系，下面看一下如何判断文档之间的关系了。<br>首先，一个文档有很多词(Term)组成，如search, lucene, full-text, this, a, what等。<br>其次对于文档之间的关系，不同的Term重要性不同，比如对于本篇文档，search, Lucene, full-text就相对重要一些，this, a , what可能相对不重要一些。所以如果两篇文档都包含search, Lucene，fulltext，这两篇文档的相关性好一些，然而就算一篇文档包含this, a, what，另一篇文档不包含this, a, what，也不能影响两篇文档的相关性。<br>因而判断文档之间的关系，首先找出哪些词(Term)对文档之间的关系最重要，如search, Lucene, fulltext。然后判断这些词(Term)之间的关系。</p>
<p>找出词(Term)对文档的重要性的过程称为计算词的权重(Term weight)的过程。<br>计算词的权重(term weight)有两个参数，第一个是词(Term)，第二个是文档(Document)。<br>词的权重(Term weight)表示此词(Term)在此文档中的重要程度，越重要的词(Term)有越大的权重(Term weight)，因而在计算文档之间的相关性中将发挥更大的作用。<br>判断词(Term)之间的关系从而得到文档相关性的过程应用一种叫做向量空间模型的算法(Vector Space Model)。</p>
<p>下面仔细分析一下这两个过程：</p>
<ol>
<li><p>计算权重(Term weight)的过程。<br>影响一个词(Term)在一篇文档中的重要性主要有两个因素：<br>Term Frequency (tf)：即此Term在此文档中出现了多少次。tf 越大说明越重要。<br>Document Frequency (df)：即有多少文档包含次Term。df 越大说明越不重要。<br>容易理解吗？词(Term)在文档中出现的次数越多，说明此词(Term)对该文档越重要，如“搜索”这个词，在本文档中出现的次数很多，说明本文档主要就是讲这方面的事的。然而在一篇英语文档中，this出现的次数更多，就说明越重要吗？不是的，这是由第二个因素进行调整，第二个因素说明，有越多的文档包含此词(Term), 说明此词(Term)太普通，不足以区分这些文档，因而重要性越低。<br>这也如我们程序员所学的技术，对于程序员本身来说，这项技术掌握越深越好（掌握越深说明花时间看的越多，tf越大），找工作时越有竞争力。然而对于所有程序员来说，这项技术懂得的人越少越好（懂得的人少df小），找工作越有竞争力。人的价值在于不可替代性就是这个道理。<br>道理明白了，<br>这仅仅只term weight计算公式的简单典型实现。实现全文检索系统的人会有自己的实现，Lucene就与此稍有不同。</p>
</li>
<li><p>判断Term之间的关系从而得到文档相关性的过程，也即向量空间模型的算法(VSM)。<br>我们把文档看作一系列词(Term)，每一个词(Term)都有一个权重(Term weight)，不同的词(Term)根据自己在文档中的权重来影响文档相关性的打分计算。<br>于是我们把所有此文档中词(term)的权重(term weight) 看作一个向量。<br>Document = {term1, term2, …… ,term N}<br>Document Vector = {weight1, weight2, …… ,weight N}<br>同样我们把查询语句看作一个简单的文档，也用向量来表示。<br>Query = {term1, term 2, …… , term N}<br>Query Vector = {weight1, weight2, …… , weight N}<br>我们把所有搜索出的文档向量及查询向量放到一个N维空间中，每个词(term)是一维。</p>
</li>
</ol>
<p>我们认为两个向量之间的夹角越小，相关性越大。<br>所以我们计算夹角的余弦值作为相关性的打分，夹角越小，余弦值越大，打分越高，相关性越大。<br>有人可能会问，查询语句一般是很短的，包含的词(Term)是很少的，因而查询向量的维数很小，而文档很长，包含词(Term)很多，文档向量维数很大。你的图中两者维数怎么都是N呢？<br>在这里，既然要放到相同的向量空间，自然维数是相同的，不同时，取二者的并集，如果不含某个词(Term)时，则权重(Term Weight)为0。<br>相关性打分公式如下：<br>举个例子，查询语句有11个Term，共有三篇文档搜索出来。其中各自的权重(Term weight)，如下表格。</p>
<p>于是文档二相关性最高，先返回，其次是文档一，最后是文档三。<br>到此为止，我们可以找到我们最想要的文档了。<br>说了这么多，其实还没有进入到Lucene，而仅仅是信息检索技术(Information retrieval)中的基本理论，然而当我们看过Lucene后我们会发现，Lucene是对这种基本理论的一种基本的的实践。所以在以后分析Lucene的文章中，会常常看到以上理论在Lucene中的应用。<br>在进入Lucene之前，对上述索引创建和搜索过程所一个总结，如图：<br>此图参照<a href="http://www.lucene.com.cn/about.htm中文章《开放源代码的全文检索引擎Lucene》" target="_blank" rel="external">http://www.lucene.com.cn/about.htm中文章《开放源代码的全文检索引擎Lucene》</a></p>
<p>Lucene的全文检索是基于对索引的搜索，所谓索引是通过Lucene高效的cross-reference算法创建的二进制文件，在学习 Lucene之前需要我们仔细观察Lucene的索引库创建以及查询机制。<br>1.创建索引库<br>为什么建立索引，在大文件或索引大量文件时，顺序扫描是极其缓慢，低效的。索引的引入，就是为了快速搜索大量文本，索引的概念引入：快速搜大量文本，你必须首先并将其转换可以让你快速搜索它的格式，消除缓慢顺序扫描过程。这个转换被称为引且其输出被称为一个索引。因此我们这里给的定义：把文本信息提取来,并且重新组织的部分我们称这内容为索引。这里我们可以样理解所谓的索引是一种数据该数据允许你快速随机访问数据文件。索引是一种特殊的数据结构文件，一般保存在文件系统上。</p>
<ul>
<li>1.1获取内容<br>lucene作为核心的搜索库，不提供任何功能获取内容，数据来源取决你的应用、软件，也可以使用开源抓取工具Solr等。</li>
<li>1.2构建Document<br>获取内容之后，我们需要将文件转换为一系列的Document,以便于搜索引擎搜索。每个Document又是由一系列的命名的Field组成。<br>例如我们拿到一篇文章可以需要将该篇文章转换为一个Document对象，那么对于这个对象我们可以认为它是由若干Field组成。每一个Field实就是即将被索引的文章属性。例如文章的 author 、title、content、 price 、url等属性。<br>对Document的另外一个问题就是对于每Document或者是Field进行加权操作。<br>这些应用需要我们在创建一个Document或者是Field时候指，定例如：你想自己的新闻稿第一个被收索到。这都需要我们对文档进行加权操作。</li>
<li>1.3分词Analyzer Docuement<br>一个文本信息不会被直接索引，我们需要将进行步预处理。事实上一般是将一个字符串拆封成若干的短语单元我们称作为 tokens,这就是我们在创建的Analyzer Document的实际所做事情。每一个Token的我们可以大致的认为是一个字的信息。</li>
<li><p>1.4创建索引<br>在创建索引的过程中， Document会被添加到索引库，仅调用Lucene的API就可以完成了相应索引库的简历。</p>
<p>2.搜索索引<br>搜索是指寻找一个索引词所处Document的过程。搜索内容质量有两个 的过程。搜索内容质量有两个 的过程。搜索内容质量有两个指标 精确度以及搜索命中率<br>Document是Lucene索引库的基本组成单元，代表着一条用户搜索记录，实际上我们对Lucene的搜索无外乎指就是对索引库中Document的搜索。<br>Field作为是Document的组成部分，代表着每一条记录所要存储项信息，同样该对象存储的信息将会被拆分为若干个字单元，而该单元中的信息根据需要也可以存入到Lucene的索引库。<br>Analyzer作为Lucene的核心类，主要是将Field的每一个字段分解成若干个单元，然后将拆分的若干个子单元创建索引库，事实上该类主要将一段字符文本拆分成TokenStream对象，该对象中保存了分词的一些信息。</p>
<pre><code class="bash">//1.创建 directory
String path=<span class="string">"F:/Lucene/index"</span>;
Directory directory=FSDirectory.open(new File(path));
//2.创建标准分词器
Analyzer analyzer=new StandardAnalyzer(Version.LUCENE_35);
//3.创建 indexWriterConfiger 
IndexWriterConfig config=new IndexWriterConfig(Version.LUCENE_35,analyzer);
//4.创建 indexWriter
IndexWriter indexWriter=new IndexWriter(directory, config);
//5.创建 document
Document document=new Document();
Field titleField=new Field(<span class="string">"title"</span>, <span class="string">"kaine learning"</span>, Store.YES, Index.NOT_ANALYZED);
Field authField=new Field(<span class="string">"auth"</span>, <span class="string">"yu"</span>, Store.YES, Index.NOT_ANALYZED);
Field contentField=new Field(<span class="string">"content"</span>, <span class="string">"hello,every one this a good book, should learn it hard."</span>, Store.YES, Index.ANALYZED);
Field dateField=new Field(<span class="string">"date"</span>, <span class="string">"2017-07-06"</span>, Store.YES, Index.NOT_ANALYZED);
Field pathField=new Field(<span class="string">"path"</span>, <span class="string">"C:/file/private/java/lucene"</span>, Store.YES,Index.NOT_ANALYZED);
document.add(titleField);
document.add(authField);
document.add(contentField);
document.add(dateField);
document.add(pathField);
//6.创建一个 document
indexWriter.addDocument(document);
//7.提交信息
indexWriter.commit();
indexWriter.close();
</code></pre>
</li>
</ul>
<p>索引搜索</p>
<pre><code class="bash">//1.创建 directory
String path=<span class="string">"F:/Lucen/index"</span>;
Directory directory=FSDirectory.open(new File(path));
//2.创建标准分词器
Analyzer analyzer=new StandardAnalyzer(Version.LUCENE_35);
//3.创建 IndexReader
IndexReader indexReader=IndexReader.open(directory);
//4.创建 IndexSearch
IndexSearcher indexSearcher=new IndexSearcher(indexReader); 
//5.创建 Term
Term term=new Term(<span class="string">"title"</span>, <span class="string">"kaine learning"</span>);
//6.创建 QueryQueryQueryQueryQuery
Query query=new TermQuery(term);
//7 获取 TopDocs
TopDocs topDocs=indexSearcher.search(query, 100);
// 打印总共查询到的文档
System.out.println(<span class="string">"总共查询到： "</span>topDocs.totalHits+<span class="string">"条记录"</span>);
//8.获取 ScoreDoc
ScoreDoc[] scoreDocs=topDocs.scoreDocs;
<span class="keyword">for</span>(int i=0;i&lt;scoreDocs.length;i++){//获取Document对象
int docId=scoreDocs[i].doc;
Document doc=indexSearcher.doc(docId);
System.out.println(<span class="string">"~~~~~~~~~~~~"</span>);
System.out.println(<span class="string">"文章标题"</span>+doc.get(<span class="string">"title"</span>));
System.out.println(<span class="string">"文章作者"</span>+doc.get(<span class="string">"auth"</span>));
System.out.println(<span class="string">"文章内容"</span>+doc.get(<span class="string">"content"</span>));
System.out.println(<span class="string">"文章日期"</span>+doc.get(<span class="string">"date"</span>));
System.out.println(<span class="string">"文章路径"</span>+doc.get(<span class="string">"path"</span>));
}
//9.关闭 indexSearch
indexSearcher.close();
//10.关闭 indexReader
indexReader.close();
</code></pre>
<p> 总结：</p>
<ol>
<li><p>索引过程：<br>1) 有一系列被索引文件<br>2) 被索引文件经过语法分析和语言处理形成一系列词(Term)。<br>3) 经过索引创建形成词典和反向索引表。<br>4) 通过索引存储将索引写入硬盘。</p>
</li>
<li><p>搜索过程：<br>a) 用户输入查询语句。<br>b) 对查询语句经过语法分析和语言分析得到一系列词(Term)。<br>c) 通过语法分析得到一个查询树。<br>d) 通过索引存储将索引读入到内存。<br>e) 利用查询树搜索索引，从而得到每个词(Term)的文档链表，对文档链表进行交，差，并得到结果文档。<br>f) 将搜索到的结果文档对查询的相关性进行排序。<br>g) 返回查询结果给用户。</p>
</li>
</ol>
<p>索引组件<br>被索引的文档用Document对象表示。<br>IndexWriter通过函数addDocument将文档添加到索引中，实现创建索引的过程。<br>Lucene的索引是应用反向索引。<br>当用户有请求时，Query代表用户的查询语句。<br>IndexSearcher通过函数search搜索Lucene Index。<br>IndexSearcher计算term weight和score并且将结果返回给用户。<br>返回给用户的文档集合用TopDocsCollector表示。</p>
<p>索引模块<br>Lucene的analysis模块主要负责词法分析及语言处理而形成Term。<br>Lucene的index模块主要负责索引的创建，里面有IndexWriter。<br>Lucene的store模块主要负责索引的读写。<br>Lucene的QueryParser主要负责语法分析。<br>Lucene的search模块主要负责对索引的搜索。<br>Lucene的similarity模块主要负责对相关性打分的实现。</p>
<p>索引过程如下：<br>创建一个IndexWriter用来写索引文件，它有几个参数，INDEX_DIR就是索引文件所存放的位置，Analyzer便是用来对文档进行词法分析和语言处理的。<br>创建一个Document代表我们要索引的文档。<br>将不同的Field加入到文档中。我们知道，一篇文档有多种信息，如题目，作者，修改时间，内容等。不同类型的信息用不同的Field来表示，在本例子中，一共有两类信息进行了索引，一个是文件路径，一个是文件内容。其中FileReader的SRC_FILE就表示要索引的源文件。<br>IndexWriter调用函数addDocument将索引写到索引文件夹中。<br>搜索过程如下：<br>IndexReader将磁盘上的索引信息读入到内存，INDEX_DIR就是索引文件存放的位置。<br>创建IndexSearcher准备进行搜索。<br>创建Analyer用来对查询语句进行词法分析和语言处理。<br>创建QueryParser用来对查询语句进行语法分析。<br>QueryParser调用parser进行语法分析，形成查询语法树，放到Query中。<br>IndexSearcher调用search对查询语法树Query进行搜索，得到结果TopScoreDocCollector。</p>

        </div>

        <blockquote class="post-copyright">
    <div class="content">
        
<span class="post-time">
    最后更新时间：<time datetime="2017-07-06T08:36:44.157Z" itemprop="dateUpdated">2017年7月6日 16:36</time>
</span><br>


        如要转载请注明出处：<a href="/2017/07/06/lucene/" target="_blank" rel="external">http://fish_08.oschina.io/2017/07/06/lucene/</a>
    </div>
    <footer>
        <a href="http://fish_08.oschina.io">
            <img src="/img/avatar.jpg" alt="于亮">
            于亮
        </a>
    </footer>
</blockquote>

        
<div class="page-reward">
    <a id="rewardBtn" href="javascript:;" class="page-reward-btn waves-effect waves-circle waves-light">赏</a>
</div>



        <div class="post-footer">
            
	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/lucene/">lucene</a></li></ul>


            
<div class="page-share-wrap">
    

<div class="page-share" id="pageShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://fish_08.oschina.io/2017/07/06/lucene/&title=《lucene》 — 尼古拉斯-鱼丸博客&pic=http://fish_08.oschina.io/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://fish_08.oschina.io/2017/07/06/lucene/&title=《lucene》 — 尼古拉斯-鱼丸博客&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://fish_08.oschina.io/2017/07/06/lucene/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《lucene》 — 尼古拉斯-鱼丸博客&url=http://fish_08.oschina.io/2017/07/06/lucene/&via=http://fish_08.oschina.io" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://fish_08.oschina.io/2017/07/06/lucene/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>



    <a href="javascript:;" id="shareFab" class="page-share-fab waves-effect waves-circle">
        <i class="icon icon-share-alt icon-lg"></i>
    </a>
</div>



        </div>
    </div>

    
<nav class="post-nav flex-row flex-justify-between">
  
    <div class="waves-block waves-effect prev">
      <a href="/2017/07/06/zookeeper/" id="post-prev" class="post-nav-link">
        <div class="tips"><i class="icon icon-angle-left icon-lg icon-pr"></i> Prev</div>
        <h4 class="title">zookeeper</h4>
      </a>
    </div>
  

  
    <div class="waves-block waves-effect next">
      <a href="/2017/07/04/redis/" id="post-next" class="post-nav-link">
        <div class="tips">Next <i class="icon icon-angle-right icon-lg icon-pl"></i></div>
        <h4 class="title">redis</h4>
      </a>
    </div>
  
</nav>



    







</article>

<div id="reward" class="page-modal reward-lay">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <h3 class="reward-title">
        <i class="icon icon-quote-left"></i>
        谢谢包子~
        <i class="icon icon-quote-right"></i>
    </h3>
    <ul class="reward-items">
        
        <li>
            <img src="/img/wechat.png" title="微信打赏二维码" alt="微信打赏二维码">
            <p>微信</p>
        </li>
        

        
        <li>
            <img src="/img/alipay.png" title="支付宝打赏二维码" alt="支付宝打赏二维码">
            <p>支付宝</p>
        </li>
        
    </ul>
</div>



</div>

        <footer class="footer">
    <div class="top">
        
<p>
    <span id="busuanzi_container_site_uv" style='display:none'>
        站点总访客数：<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv" style='display:none'>
        站点总访问量：<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


        <p>
            <span><a href="/atom.xml" target="_blank" class="rss" title="rss"><i class="icon icon-lg icon-rss"></i></a></span>
            <span>博客内容遵循 <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">知识共享 署名 - 非商业性 - 相同方式共享 4.0协议</a></span>
        </p>
    </div>
    <div class="bottom">
        <p>
            <span>Power by <a href="http://hexo.io/" target="_blank">Hexo</a> Theme <a href="http://fish_08.oschina.io/" target="_blank">yuliang</a></span>
            <span>尼古拉斯-鱼丸博客 &copy; 2015 - 2018</span>
        </p>
    </div>
</footer>

    </main>
    <div class="mask" id="mask"></div>
<a href="javascript:;" id="gotop" class="waves-effect waves-circle waves-light"><span class="icon icon-lg icon-chevron-up"></span></a>



<div class="global-share" id="globalShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://fish_08.oschina.io/2017/07/06/lucene/&title=《lucene》 — 尼古拉斯-鱼丸博客&pic=http://fish_08.oschina.io/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://fish_08.oschina.io/2017/07/06/lucene/&title=《lucene》 — 尼古拉斯-鱼丸博客&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://fish_08.oschina.io/2017/07/06/lucene/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《lucene》 — 尼古拉斯-鱼丸博客&url=http://fish_08.oschina.io/2017/07/06/lucene/&via=http://fish_08.oschina.io" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://fish_08.oschina.io/2017/07/06/lucene/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>


<div class="page-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <img src="" alt="微信分享二维码">
</div>




    <script src="//cdn.bootcss.com/node-waves/0.7.4/waves.min.js"></script>
<script>
var BLOG = { ROOT: '/', SHARE: true, REWARD: true };



</script>

<script src="/js/main.min.js?v=1.6.7"></script>


<div class="search-panel" id="search-panel">
    <ul class="search-result" id="search-result"></ul>
</div>
<template id="search-tpl">
<li class="item">
    <a href="{path}" class="waves-block waves-effect">
        <div class="title ellipsis" title="{title}">{title}</div>
        <div class="flex-row flex-middle">
            <div class="tags ellipsis">
                {tags}
            </div>
            <time class="flex-col time">{date}</time>
        </div>
    </a>
</li>
</template>

<script src="/js/search.min.js?v=1.6.7" async></script>






<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>


</body>
</html>
